package com.jerry.template.views;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Xfermode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.ImageView;

import com.jerry.template.R;

import java.lang.ref.WeakReference;

/**
 * Created by chenhuan on 2016/5/13.
 */
public class RoundImageView extends ImageView{
    //虚引用来保存Bitmap，内存不够，则虚拟机立即回收存放在虚拟机的内存
    private WeakReference<Bitmap> weakBitmap;

    private Paint paint;

    //取上层交集
    private Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);

    //图片显示类型
    public static final int TYPE_CIRCLE = 0;
    public static final int TYPE_ROUND = 1;
    //type用于来设置从自定义控件中获取的类型
    private int type = TYPE_CIRCLE;

    //圆角大小或圆的半径
    public static final int RADIUS_DEFAULT = 10;

    //保存从自定义控件 获取的圆角大小或半径
    private int mRadius;

    public RoundImageView(Context context){
        this(context, null);
    }

    public RoundImageView(Context context, AttributeSet attrs){
        super(context, attrs);
        //初始化视图
        intiView(context, attrs);
    }

    private void intiView(Context context, AttributeSet attrs){
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //获取自定义属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
        //获取类型
        type = array.getInt(R.styleable.RoundImageView_type, TYPE_CIRCLE);
        //获取圆角大小 半径
        //第二个参数是个像素值
        int pxv = dp2px(RADIUS_DEFAULT);
        mRadius = array.getDimensionPixelOffset(R.styleable.RoundImageView_radius, pxv);
        array.recycle();
    }

    //dp转换为px
    private int dp2px(int dpv){
        //在自定义View中获取屏幕测量对象
        DisplayMetrics metrics = getResources().getDisplayMetrics();
        //获取以dip为单位
        int dip = TypedValue.COMPLEX_UNIT_DIP;
        //将dp转换成px
        float pxv = TypedValue.applyDimension(dip, dpv, metrics);
        return (int) pxv;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //类型如果是对应的圆形图片，则设置宽高一致
        if(type == TYPE_CIRCLE){
            int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
            setMeasuredDimension(size, size);
        }
    }

    @Override
    protected void onDraw(Canvas canvas){
        //super.onDraw(canvas);
        //判断虚引用中是否保存着Bitmap
        //获取ImageView设置的资源
        Drawable drawable = getDrawable();

        //Bitmap bitmap = weakBitmap.get() == null ? null : weakBitmap.get();
        Bitmap bitmap = weakBitmap == null ? null : weakBitmap.get();
        if(bitmap == null){
            if(drawable != null){
                // 获取资源本身固有的宽高
                int dWidth = drawable.getIntrinsicWidth();
                int dHeight = drawable.getIntrinsicHeight();
                //缩放处理
                //Bitmap.Config.ARGB_8888 一个像素点包含8个字节
                //Bitmap.Config.RGB_565 一个像素点包含4个字节
                bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
                //创建一个画布，在这个画布上绘制图片
                Canvas drawableCanvas = new Canvas(bitmap);
                //定义缩放大小
                float scale = 0f;
                if(type == TYPE_ROUND){
                    //getWidth() 自己定义的宽度  130dp
                    //dWidth 原图片宽度  438px
                    scale = Math.max(getWidth() / dWidth * 1.0f, getHeight() / dHeight * 1.0f);
                }else{
                    //这种情况下，getWidth()==getHeight()
                    scale = getWidth() * 1.0f / Math.min(dWidth, dHeight);
                }
                //根据此比例来缩放图片
                drawable.setBounds(0, 0, (int) (scale * dWidth), (int) (scale * dHeight));
                //调用此方法，画布上的图片就是会缩小的
                drawable.draw(drawableCanvas);
                //进行xforeMode图层处理
                //再绘制一个圆角矩形或者一个圆来画到对应的画布上，使用PorterDuff.Mode.DST_IN图层模式
                Bitmap roundBitmap = getRoundBitmap();
                //清理绘制内容
                paint.reset();
                //滤镜效果去掉
                paint.setFilterBitmap(false);
                //设置图层模式
                paint.setXfermode(xfermode);
                drawableCanvas.drawBitmap(roundBitmap, 0, 0, paint);
                //通过ImageView资源创建的画布上对应的bitmap
                paint.setXfermode(null);
                canvas.drawBitmap(bitmap, 0, 0, null);

                //把已经绘制出来的Bitmap存放到weakBitmap虚引用中
                weakBitmap = new WeakReference<Bitmap>(bitmap);
            }
        }

        //如果虚引用中有对应绘制的Bitmap，则直接绘制
        else{
            paint.setXfermode(null);
            canvas.drawBitmap(bitmap, 0, 0, null);
        }
    }

    //复写重绘方法
    @Override
    public void invalidate(){

        if(weakBitmap!=null){
            Bitmap bitmap = weakBitmap.get();
            if(bitmap != null){
                //回收Bitmap的内存
                bitmap.recycle();
                bitmap = null;
            }
            //回收虚引用的内容
            weakBitmap.clear();
            weakBitmap = null;
        }

        super.invalidate();
    }

    //获取绘制的圆角矩形或圆
    public Bitmap getRoundBitmap(){
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.BLACK);
        if(type == TYPE_ROUND){
            canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), mRadius, mRadius, paint);
        }else{
            int radius = mRadius > (getWidth() / 2) ? (getWidth() / 2) : mRadius;
            canvas.drawCircle(((float) getWidth()) / 2, ((float) getHeight()) / 2, radius, paint);
        }
        return bitmap;
    }

    public void setRadius(int radius){
        mRadius = radius;
        invalidate();
    }
}
